
package com.youlai.system.common.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.format.annotation.DateTimeFormat;

import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期工具类
 *
 * @author haoxr
 * @since 2.4.2
 */
public class CommUtils {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DecimalFormat decimalFormat = new DecimalFormat("0.0");

    /**
     * 区间日期格式化为数据库日期格式
     * <p>
     * eg：2021-01-01 → 2021-01-01 00:00:00
     *
     * @param obj                要处理的对象
     * @param startTimeFieldName 起始时间字段名
     * @param endTimeFieldName   结束时间字段名
     */
    public static void toDatabaseFormat(Object obj, String startTimeFieldName, String endTimeFieldName) {
        Field startTimeField = ReflectUtil.getField(obj.getClass(), startTimeFieldName);
        Field endTimeField = ReflectUtil.getField(obj.getClass(), endTimeFieldName);

        if (startTimeField != null) {
            processDateTimeField(obj, startTimeField, startTimeFieldName, "yyyy-MM-dd 00:00:00");
        }

        if (endTimeField != null) {
            processDateTimeField(obj, endTimeField, endTimeFieldName, "yyyy-MM-dd 23:59:59");
        }
    }

    /**
     * 处理日期字段
     *
     * @param obj           要处理的对象
     * @param field         字段
     * @param fieldName     字段名
     * @param targetPattern 目标数据库日期格式
     */
    private static void processDateTimeField(Object obj, Field field, String fieldName, String targetPattern) {
        Object fieldValue = ReflectUtil.getFieldValue(obj, fieldName);
        if (fieldValue != null) {
            // 得到原始的日期格式
            String pattern = field.isAnnotationPresent(DateTimeFormat.class) ? field.getAnnotation(DateTimeFormat.class).pattern() : "yyyy-MM-dd";
            // 转换为日期对象
            DateTime dateTime = DateUtil.parse(StrUtil.toString(fieldValue), pattern);
            // 转换为目标数据库日期格式
            ReflectUtil.setFieldValue(obj, fieldName, dateTime.toString(targetPattern));
        }
    }

    /**
     * 获取当前时间并格式化为指定格式。
     *
     * @return 格式化后的当前时间字符串
     */
    public static String getCurrentDateTime() {
        LocalDateTime now = LocalDateTime.now();
        return now.format(formatter);
    }


    /**
     * 解析协议格式字符串并提取标准化节点路径
     * 从包含命名空间声明和带引号节点段的输入参数中，提取并拼接符合规范的节点路径。
     * 典型输入格式：ns=<命名空间>;s="<节点段1>"."<节点段2>"...
     *
     * @param input 原始协议参数字符串，需包含"s="起始的节点声明部分（示例：ns=3;s="DBLine"."A002_Press"）
     * @return 标准化节点路径字符串，使用点号连接各节点段，保留原始段内容格式（示例返回：DBLine.A002_Press）
     *
     * @implNote 处理逻辑：
     * 1. 定位"s="起始位置，提取后续全部内容
     * 2. 使用正则匹配所有双引号包裹的节点段
     * 3. 自动过滤转义符号，保留段内原始字符（包括下划线）
     * 4. 用点号连接所有匹配到的节点段
     */
    public static String parseParameter(String input) {
        // 直接定位s=后的内容
        int sStart = input.indexOf("s=");
        if (sStart == -1) return "";

        // 提取s=后的所有内容
        String sContent = input.substring(sStart + 2);

        // 正则匹配双引号内容
        List<String> components = new ArrayList<>();
        Matcher m = Pattern.compile("\"([^\"]*)\"").matcher(sContent);
        while (m.find()) {
            components.add(m.group(1)); // 直接保留原始内容
        }

        return String.join(".", components);
    }
    /**
     * 格式化返回节点
     *
     * @param"DBLine"."Real2"
     * @return DBLine.Real2
     */
    public static   String FormatNode(String input) {
        if (input == null) {
            return "";
        }
        return input.replaceAll("\"", "");
    }

    /**
     * 将浮点数格式化为保留一位小数的字符串。
     *
     * @param floatNumber 需要格式化的浮点数
     * @return 保留一位小数的字符串表示
     */
    public static String FormatFloat(float floatNumber) {
        return decimalFormat.format(floatNumber);
    }

    /**
     * 判断给定的浮点数字符串表示的值是否在其整数部分基础上加减5的范围之外。
     *
     * @param valueStr 浮点数的字符串表示
     * @return 如果值在整数部分加减5的范围之外则返回true，否则返回false
     */
    public static boolean IsOutsideRange(String valueStr,String rangeStr) {
        try {
            // 将字符串转换为浮点数
            float value = Float.parseFloat(valueStr);
            float range = Float.parseFloat(rangeStr);

            // 提取整数部分
            float intValue = (float) Math.floor(value + 0.5f); // 使用Math.floor()和0.5来四舍五入

            // 计算加减5的边界
            float lowerBound = intValue - range;
            float upperBound = intValue + range;

            // 判断是否在范围外
            return value < lowerBound || value > upperBound;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid number format: " + valueStr, e);
        }
    }


    /**
     * 判断当前值是否在上一个值的基础上加减指定浮动值的范围内。
     *
     * @param currentValue 当前值
     * @param previousValue 上一个值
     * @param tolerance 浮动值
     * @return 如果当前值在上一个值加减浮动值的范围内则返回true，否则返回false
     */
    public static boolean IsWithinTolerance(Float currentValue, Float previousValue, Integer tolerance) {
        Float lowerBound = previousValue - tolerance;
        Float upperBound = previousValue + tolerance;

        return currentValue <= lowerBound || currentValue >= upperBound;
    }

    /**
     * 生成从 start 到 end 的数字序列，并以逗号分隔的字符串形式返回。
     *
     * @param start 序列起始数字（包含）
     * @param end   序列结束数字（包含）
     * @return 从 start 到 end 的数字序列字符串
     */
    public static String generateNumberSequence(int start, int end) {
        // 使用 StringBuilder 来构建字符串，因为它是可变的，效率更高
        StringBuilder sb = new StringBuilder();
        for (int i = start; i <= end; i++) {
            sb.append(i);
            // 如果不是最后一个数字，则添加逗号
            if (i < end) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    /**
     * 生成包含指定数量的 '0' 的字符串，并以逗号分隔。
     *
     * @param count 需要生成的 '0' 的数量
     * @return 包含指定数量 '0' 的字符串
     */
    public static String generateZeroSequence(int count) {
        // 使用 StringBuilder 来构建字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append("0");
            // 如果不是最后一个 '0'，则添加逗号
            if (i < count - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

}
